#include <iostream>
#include <string>

class Student
{
public:
    // 缺省构造（无参构造）函数
    Student() { std::cout << "无参构造函数!\n"; }
    // 带参构造函数
    Student(std::string name, int age)
    {
        std::cout << "带参构造函数！\n";
        m_name = name;
        m_age = age;
    }

    // 函数调用的时候，实参传到这里的形参的过程会进行拷贝，当发生内存拷贝的时候会自动调用拷贝构造函数，拷贝构造函数如果被调用，传的是普通对象，那就又会调拷贝构造，从而无限递归调用，最终导致栈溢出
    // 所以拷贝构造是不允许传对象本身的拷贝进来的,错误写法：Student(Student s)
    // 为了防止产生对象的拷贝，要传引用，别名就不会发生拷贝
    // 函数传参的时候，如果不传引用的话，它会产生内存的拷贝，如果内存要拷贝就会自动调用拷贝构造，拷贝构造如果本身传参又是拷贝的话，那就会无限拷贝下去，从而无限递归调用，最终导致栈溢出，所以拷贝构造必须要传引用就是这个原因，别名就不会发生拷贝
    Student(Student &s)
    {
        std::cout << "拷贝构造函数!\n";
        m_name = s.m_name;
        m_age = s.m_age;
    }

    // 赋值运算符的重载 调用时机：进行赋值的时候（s1 = s）
    void operator=(Student &s)
    {
        std::cout << "赋值运算符的重载\n";
        m_name = s.m_name;
        m_age = s.m_age;
    }

    // 析构函数（释放的函数）：无返回值，函数名和类名相同 前面加~ 无参数
    // 自动调用
    // 析构函数不能重载（重载是在调用的时候根据参数数量类型顺序的不同调用不同的函数实体，析构函数是不会显示调用的，连调都不调，它都是编译器在内部处理的逻辑）
    // 不能重载就不能有参数,这两个互为因果
    ~Student()
    {
        std::cout << "析构函数!\n";
    }

    void SetName(std::string name);
    void SetAge(int age);
    void show();

private:
    // 成员变量（属性）
    std::string m_name;
    int m_age;
};

void Student::SetName(std::string name)
{
    m_name = name;
}

void Student::SetAge(int age)
{
    m_age = age;
}

void Student::show()
{
    std::cout << "学生姓名：" << m_name << " 学生年龄：" << m_age << std::endl;
}

struct Test
{
public:
    void SetA(int a)
    {
        m_a = a;
    }

    void show()
    {
        std::cout << "a = " << m_a << std::endl;
    }

private:
    int m_a;
};

int main()
{
    // 构造函数的调用是一个自动的过程
    Student s("zhangsan", 21);
    // s.show();
    // Student s1(s);   // 在构造一个对象的时候，括号里写的是另一个对象，也就是拿一个Student去构造另外一个Student，这种就称为拷贝构造
    // Student s1 = s;  // 这样写也是拷贝构造，用s去构建s1，和上面的写法等价
    Student s1;
    s1 = s; // 把s的值赋值给s1（赋值运算符的重载）
    s1.show();
    return 0;
}